This section shows how you can use callback procedures to play one sound asynchronously at a given time. "Managing Multiple Sound Channels" expands the techniques in this section to show how you can play several asynchronous sounds simultaneously.
The SndNewChannel function allows you to associate a callback procedure with a sound channel. For example, the following code opens a new sound channel for which memory has already been allocated and associates it with the callback procedure MyCallBack :
myErr := SndNewChannel(gSndChan, sampledSynth, initMono, @MyCallback);
After filling a channel created by SndNewChannel with various commands to create sound, you can then issue a callBackCmd command to the channel. When the Sound Manager encounters a callBackCmd command, it executes your callback procedure. Thus, by placing the callBackCmd command last in a channel, you can ensure that the Sound Manager executes your callback procedure only after it has processed all of the channel's other sound commands.
Be sure to issue callBackCmd commands with the SndDoCommand function and not the SndDoImmediate function. If you issue a callBackCmd command with SndDoImmediate , your callback procedure might be called before other sound commands you have issued finish executing.
A callback procedure has the following syntax:
PROCEDURE MyCallBack (chan: SndChannelPtr; cmd: SndCommand);
Because the callback procedure executes at interrupt time, it cannot access its application global variables unless the application's A5 world is set correctly. (For more information on the A5 world, see the chapter "Memory Management Utilities" in Inside Macintosh: Memory .) When called, the callback procedure is passed two parameters: a pointer to the sound channel that received the callBackCmd command and the sound command that caused the callback procedure to be called. Applications can use param1 or param2 of the sound command as flags to pass information or instructions to the callback procedure. If your callback procedure is to use your application's global data storage, it must first reset A5 to your application's A5 and then restore it on exit. For example, Listing 1-28 illustrates how to set up a callBackCmd command that contains the required A5 information in the param2 field. The MyInstallCallback function defined there must be called at a time when your application's A5 world is known to be valid.
Listing 28 Issuing a callback command
FUNCTION MyInstallCallback (mySndChan: SndChannelPtr): OSErr;
CONST
kWaitIfFull = TRUE; {wait for room in queue}
VAR
mySndCmd: SndCommand; {a sound command}
BEGIN
WITH mySndCmd DO
BEGIN
cmd := callBackCmd; {install the callback command}
param1 := kSoundComplete; {last command for this channel}
param2 := SetCurrentA5; {pass the callback the A5}
END;
MyInstallCallback := SndDoCommand(mySndChan, mySndCmd, kWaitIfFull);
END;
In this function, kSoundComplete is an application-defined constant that indicates that the requested sound has finished playing. You could define it like this:
CONST
kSoundComplete = 1;{sound is done playing}
Because param2 of a sound command is a long integer, Listing 1-28 uses it to pass the application's A5 to the callback procedure. That allows the callback procedure to gain access to the application's A5 world.
You can also pass information to a callback routine in the userInfo field of the sound channel.
The sample callback procedure defined in Listing 1-29 can thus set A5 to access the application's global variables.
Listing 29 Defining a callback procedure
PROCEDURE MyCallback (theChan: SndChannelPtr; theCmd: SndCommand);
VAR
myA5: LongInt;
BEGIN
IF theCmd.param1 = kSoundComplete THEN
BEGIN